home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 December / CHIPNET Aralık 1997.iso / linux / redhat / misc / src / init / init.c < prev    next >
C/C++ Source or Header  |  1997-08-11  |  14KB  |  629 lines

  1. /*
  2.  * init.c
  3.  * 
  4.  * This is the install type init 
  5.  *
  6.  * Erik Troan (ewt@redhat.com)
  7.  *
  8.  * Copyright 1996 Red Hat Software 
  9.  *
  10.  * This software may be freely redistributed under the terms of the GNU
  11.  * public license.
  12.  *
  13.  * You should have received a copy of the GNU General Public License
  14.  * along with this program; if not, write to the Free Software
  15.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  *
  17.  */
  18.  
  19. #include <ctype.h>
  20. #include <fcntl.h>
  21. #include <linux/fs.h>
  22. #include <linux/if.h>
  23. #include <signal.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <sys/ioctl.h>
  28. #include <sys/mount.h>
  29. #include <sys/socket.h>
  30. #include <sys/stat.h>
  31. #include <sys/time.h>
  32. #include <sys/types.h>
  33. #include <sys/un.h>
  34. #include <sys/wait.h>
  35. #include <unistd.h>
  36. #include <sys/ioctl.h>
  37. #include <termios.h>
  38.  
  39. #ifdef __alpha__
  40. #include <sys/reboot.h>
  41. #endif
  42.  
  43. /* 
  44.  * this needs to handle the following cases:
  45.  *
  46.  *    1) run from a CD root filesystem
  47.  *    2) run from a read only nfs rooted filesystem
  48.  *      3) run from a floppy
  49.  *    4) run from a floppy that's been loaded into a ramdisk 
  50.  *
  51.  */
  52.  
  53. int testing;
  54.  
  55. #define __LIBRARY__
  56. #include <linux/unistd.h>
  57. #ifndef __alpha__
  58. # define __NR_sys_syslog __NR_syslog
  59. _syscall3(int,syslog,int, type, char *, buf, int, len);
  60. #else
  61. # define syslog klogctl
  62. #endif
  63.  
  64. void fatal_error(int usePerror) {
  65.     if (usePerror) 
  66.     perror("failed:");
  67.     else
  68.     fprintf(stderr, "failed.\n");
  69.  
  70.     fprintf(stderr, "\nI can't recover from this.\n");
  71.     while (1) ;
  72. }
  73.  
  74. int doMke2fs(char * device, char * size) {
  75.     char * args[] = { "/usr/bin/mke2fs", NULL, NULL, NULL };
  76.     int pid, status;
  77.  
  78.     args[1] = device;
  79.     args[2] = size;
  80.  
  81.     if (!(pid = fork())) {
  82.     /* child */
  83.     execv("/usr/bin/mke2fs", args);
  84.     fatal_error(1);
  85.     }
  86.  
  87.     wait(&status);
  88.     
  89.     return 0;
  90. }
  91.  
  92. int hasNetConfiged(void) {
  93.     int rc;
  94.     int s;
  95.     struct ifconf configs;
  96.     struct ifreq devs[10];
  97.  
  98.     #ifdef __i386__
  99.     return 0;
  100.     #endif
  101.  
  102.     s = socket(AF_INET, SOCK_STREAM, 0);
  103.     if (s < 0) {
  104.     perror("socket");
  105.     return 0;
  106.     } else {
  107.     /* this is just good enough to tell us if we have anything 
  108.        configured */
  109.     configs.ifc_len = sizeof(devs);
  110.     configs.ifc_buf = (void *) devs;
  111.  
  112.     rc = ioctl(s, SIOCGIFCONF, &configs);
  113.     if (rc < 0) {
  114.         perror("SIOCGIFCONF");
  115.         return 0;
  116.     }
  117.     if (configs.ifc_len == 0) {
  118.         return 0;
  119.     }
  120.  
  121.     return 1;
  122.     }
  123.  
  124.     return 0;
  125. }
  126.  
  127. void doklog(char * fn) {
  128.     fd_set readset, unixs;
  129.     int in, out, i;
  130.     size_t s;
  131.     int sock;
  132.     struct sockaddr_un sockaddr;
  133.     char buf[1024];
  134.     int readfd;
  135.  
  136.     in = open("/proc/kmsg", O_RDONLY);
  137.     if (in < 0) {
  138.     perror("open /proc/kmsg");
  139.     return;
  140.     }
  141.  
  142.     out = open(fn, O_WRONLY);
  143.     if (out < 0) {
  144.     printf("couldn't open %s for syslog -- trying /tmp/syslog\n", fn);
  145.  
  146.     out = open("/tmp/syslog", O_WRONLY | O_CREAT | 0644);
  147.     if (out < 0) {
  148.         perror("open kmsg log");
  149.         
  150.         close(in);
  151.         return;
  152.     }
  153.     }
  154.  
  155.     /* if we get this far, we should be in good shape */
  156.  
  157.     if (fork()) {
  158.     /* parent */
  159.     close(in);
  160.     close(out);
  161.     return;
  162.     }
  163.     close(0); close(1); close(2);
  164.  
  165.     /* now open the syslog socket */
  166.     sockaddr.sun_family = AF_UNIX;
  167.     strcpy(sockaddr.sun_path, "/dev/log");
  168.     sock = socket(AF_UNIX, SOCK_STREAM, 0);
  169.     if (sock < 1) {
  170.     write(out, "socket error\n", 13);
  171.     }
  172.     if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) + 
  173.             strlen(sockaddr.sun_path))) {
  174.     write(out, "bind error\n", 11);
  175.     }
  176.     chmod("/dev/log", 0666);
  177.     if (listen(sock, 5)) {
  178.     write(out, "listen error\n", 13);
  179.     }
  180.     syslog(8, NULL, 1);
  181.  
  182.     FD_ZERO(&unixs);
  183.     while (1) {
  184.     memcpy(&readset, &unixs, sizeof(unixs));
  185.  
  186.     FD_SET(sock, &readset);
  187.     FD_SET(in, &readset);
  188.  
  189.     i = select(FD_SETSIZE, &readset, NULL, NULL, NULL);
  190.     if (i <= 0) continue;
  191.  
  192.     if (FD_ISSET(in, &readset)) {
  193.         i = read(in, buf, sizeof(buf));
  194.         if (i > 0) write(out, buf, i);
  195.     } 
  196.  
  197.     for (readfd = 0; readfd < FD_SETSIZE; ++readfd) {
  198.         if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs)) {
  199.         i = read(readfd, buf, sizeof(buf));
  200.         if (i > 0) {
  201.             write(out, buf, i);
  202.             write(out, "\n", 1);
  203.         } else if (i == 0) {
  204.             /* socket closed */
  205.             close(readfd);
  206.             FD_CLR(readfd, &unixs);
  207.         }
  208.         }
  209.     }
  210.  
  211.     if (FD_ISSET(sock, &readset)) {
  212.         i = sizeof(sockaddr);
  213.         readfd = accept(sock, (struct sockaddr *) &sockaddr, &s);
  214.         if (readfd < 0) {
  215.         /*write(out, "error in accept\n", 16);*/
  216.         } else {
  217.         FD_SET(readfd, &unixs);
  218.         }
  219.     }
  220.     }    
  221. }
  222.  
  223. #if defined(__alpha__)
  224. char * findKernel(void) {
  225.     char * dev, * file;
  226.     struct stat sb;
  227.  
  228.     dev = getenv("bootdevice");
  229.     file = getenv("bootfile");
  230.  
  231.     if (!dev || !file) {
  232.     printf("I can't find your kernel. When you are booting"
  233.         " from a CDROM, you must pass\n");
  234.     printf("the bootfile argument to the kernel if your"
  235.         " boot loader doesn't do so automatically.\n");
  236.     printf("\n");
  237.     printf("You should now reboot your system and try "    
  238.         "again\n");
  239.  
  240.     while (1) ;
  241.     }
  242.  
  243.     if (!strcmp(dev, "fd0")) {
  244.     if (!strcmp(file, "vmlinux.gz")) {
  245.         printf("The kernel on a boot floppy must be named vmlinux.gz. "
  246.                "You\n");
  247.         printf("are using a kernel named %s instead. You'll have "
  248.            "to\n", file);
  249.         printf("fix this and try again.\n");
  250.  
  251.         while (1) ;
  252.     }
  253.  
  254.     return NULL;
  255.     } else {
  256.     if (stat(file, &sb)) {
  257.         printf("I can't find your kernel. When you are booting"
  258.             " from a CDROM, you must pass\n");
  259.         printf("the bootfile argument to the kernel if your"
  260.             " boot loader doesn't do so automatically.\n");
  261.         printf("\n");
  262.         printf("You should now reboot your system and try "    
  263.             "again\n");
  264.  
  265.         while (1) ;
  266.     }
  267.  
  268.     return file;
  269.     }
  270. }
  271. #endif
  272.  
  273. int setupTerminal(int fd) {
  274.     struct winsize winsize;
  275.  
  276.     if (ioctl(fd, TIOCGWINSZ, &winsize)) {
  277.     printf("failed to get winsize");
  278.     fatal_error(1);
  279.     }
  280.  
  281.     winsize.ws_row = 24;
  282.     winsize.ws_col = 80;
  283.  
  284.     if (ioctl(fd, TIOCSWINSZ, &winsize)) {
  285.     printf("failed to set winsize");
  286.     fatal_error(1);
  287.     }
  288.  
  289.     putenv("TERM=vt100");
  290.  
  291.     return 0;
  292. }
  293.  
  294. void unmountFilesystems(void) {
  295.     int fd, size;
  296.     char buf[65535];            /* this should be big enough */
  297.     char * chptr, * start;
  298.     struct {
  299.     char * name;
  300.     int len;
  301.     } filesystems[500], tmp;
  302.     int numFilesystems = 0;
  303.     int i, j;
  304.  
  305.     fd = open("/proc/mounts", O_RDONLY);
  306.     if (fd < 1) {
  307.     perror("failed to open /proc/mounts");
  308.     sleep(2);
  309.     return;
  310.     }
  311.  
  312.     size = read(fd, buf, sizeof(buf) - 1);
  313.     buf[size] = '\0';
  314.  
  315.     close(fd);
  316.  
  317.     chptr = buf;
  318.     while (*chptr) {
  319.     while (*chptr != ' ') chptr++;
  320.     chptr++;
  321.     start = chptr;
  322.     while (*chptr != ' ') chptr++;
  323.     *chptr++ = '\0';
  324.     filesystems[numFilesystems].name = start;
  325.     filesystems[numFilesystems].len = strlen(start);
  326.     numFilesystems++;
  327.     while (*chptr != '\n') chptr++;
  328.     chptr++;
  329.     }
  330.  
  331.     /* look ma, a *bubble* sort */
  332.     for (i = 0; i < (numFilesystems - 1); i++) {
  333.     for (j = i; j < numFilesystems; j++) {
  334.         if (filesystems[i].len < filesystems[j].len) {
  335.         tmp = filesystems[i];
  336.         filesystems[i] = filesystems[j];
  337.         filesystems[j] = tmp;
  338.         }
  339.     }
  340.     }
  341.  
  342.     /* -1 because the last one will always be '/' */
  343.     for (i = 0; i < numFilesystems - 1; i++) {
  344.     printf("\t%s", filesystems[i].name); fflush(stdout);
  345.     if (!testing) {
  346.         if (umount(filesystems[i].name)) {
  347.         printf(" failed: %s", strerror(errno));
  348.         }
  349.     }
  350.     printf("\n");
  351.     }
  352. }
  353.  
  354. void readargs(int * isRescue, int * isSerial) {
  355.     char buf[512];
  356.     int fd;
  357.     int size;
  358.     int done = 0;
  359.     char * start, * end;
  360.  
  361.     printf("opening /proc/cmdline... "); fflush(stdout);
  362.  
  363.     if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) fatal_error(1);
  364.  
  365.     size = read(fd, buf, sizeof(buf) - 1);
  366.     buf[size] = '\0';
  367.     close(fd);
  368.  
  369.     printf("done\n");
  370.  
  371.     printf("checking command line arguments..."); fflush(stdout);
  372.     start = buf;
  373.  
  374.     while (!done) {
  375.     while (*start && isspace(*start)) start++;
  376.     if (!(*start)) break;
  377.     
  378.     end = start;
  379.     while (*end && !isspace(*end)) end++;
  380.  
  381.     if (!*end) done = 1;
  382.     *end = '\0';
  383.  
  384.     if (!strcmp(start, "auto") ||
  385.         !strncmp(start, "BOOT_IMAGE", 10) ||
  386.         !strncmp(start, "initrd=", 7) ||
  387.         !strncmp(start, "bootdevice=", 11) ||
  388.         !strncmp(start, "bootfile=", 9) ||
  389.         !strcmp(start, "ro") ||
  390.         !strncmp(start, "root=", 5) ||
  391.         !strncmp(start, "load_ramdisk", 12) ||
  392.         !strncmp(start, "prompt_ramdisk", 14)) {
  393.         /* lilo does this for us -- we don't care */
  394.     } else if (!strcmp(start, "rescue")) {
  395.         printf("\n\trescue disk mode enabled"); fflush(stdout);
  396.         *isRescue = 1;
  397.     } else if (!strcmp(start, "serial")) {
  398.         printf("\n\tserial mode enabled"); fflush(stdout);
  399.         fflush(stdout);
  400.         *isSerial = 1;
  401.     } else {
  402.         printf("\n\tunknown option '%s'!", start); fflush(stdout);
  403.         sleep(5);
  404.     }
  405.  
  406.     start = end + 1;
  407.     }
  408.     printf("\n");
  409. }
  410.  
  411. void main(void) {
  412.     pid_t installpid, childpid;
  413.     int waitStatus;
  414.     int fd;
  415.     int nfsRoot = 0;
  416.     int roRoot = 0;
  417.     int cdRoot = 0;
  418.     int isRescue = 0;
  419.     int isSerial = 0;
  420.     int doReboot = 0;
  421.     int doShutdown =0;
  422.     #ifdef __alpha__
  423.     char * kernel;
  424.     #endif
  425.  
  426.     /* getpid() != 1 should work, by linuxrc tends to get a larger pid */
  427.     testing = (getpid() > 50);
  428.  
  429.     if (!testing) {
  430.     /* turn off screen blanking */
  431.     printf("\033[9;0]");
  432.     printf("\033[8]");
  433.     }
  434.  
  435.     printf("Red Hat install init version %s starting\n", VERSION);
  436.  
  437.     putenv("PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:"
  438.            "/mnt/bin:/mnt/usr/bin");
  439.     putenv("LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib");
  440.     putenv("HOME=/");
  441.  
  442.     printf("mounting /proc filesystem... "); fflush(stdout);
  443.     if (!testing) {
  444.     if (mount("/proc", "/proc", "proc", 0, NULL))
  445.         fatal_error(1);
  446.     }
  447.  
  448.     readargs(&isRescue, &isSerial);
  449.  
  450.     if (isSerial) {
  451.     fd = open("/dev/cua0", O_RDWR);
  452.     if (fd < 0) {
  453.         printf("failed to open /dev/cua0");
  454.         fatal_error(1);
  455.     }
  456.     write(fd, "Switching to serial console...", 29);
  457.  
  458.     /* gulp */
  459.     fflush(stdout);
  460.     fflush(stderr);
  461.     dup2(fd, 0);
  462.     dup2(fd, 1);
  463.     dup2(fd, 2);
  464.  
  465.     printf("done\n\n"); fflush(stdout);
  466.  
  467.     printf("Red Hat install init version %s using a serial console\n", 
  468.         VERSION);
  469.  
  470.     printf("remember, cereal is an important part of a nutritionally "
  471.            "balanced breakfast.\n\n");
  472.  
  473.     setupTerminal(0);
  474.  
  475.     close(fd);
  476.     }
  477.  
  478.     sethostname("localhost", 9);
  479.  
  480.     printf("done\n");
  481.  
  482.     if (!testing) 
  483.     doklog("/dev/tty4");
  484.  
  485.     printf("checking for NFS root filesystem..."); fflush(stdout);
  486.     if (hasNetConfiged()) {
  487.     printf("yes\n");
  488.     roRoot = nfsRoot = 1;
  489.     } else {
  490.     printf("no\n");
  491.     }
  492.  
  493.     if (!nfsRoot) {
  494.     printf("trying to remount root filesystem read write... ");
  495.     if (mount("/", "/", NULL, MS_REMOUNT | MS_MGC_VAL, NULL)) {
  496.         printf("failed (but that's okay)\n");
  497.     
  498.         roRoot = 1;
  499.     } else {
  500.         printf("done\n");
  501.  
  502.         /* 2.0.18 (at least) lets us remount a CD r/w!! */
  503.         printf("checking for writeable /tmp... ");
  504.         fd = open("/tmp/tmp", O_WRONLY | O_CREAT, 0644);
  505.         if (fd < 0) {
  506.         printf("no (probably a CD rooted install)\n");
  507.         roRoot = 1;
  508.         } else {
  509.         close(fd);
  510.         unlink("/tmp/tmp");
  511.         printf("yes\n");
  512.         }
  513.     }
  514.     }
  515.  
  516.     if (roRoot) {
  517.     printf("creating 100k of ramdisk space... "); fflush(stdout);
  518.     if (doMke2fs("/dev/ram", "100"))
  519.         fatal_error(0);
  520.  
  521.     printf("done\n");
  522.     
  523.     printf("mounting /tmp from ramdisk... "); fflush(stdout);
  524.     if (mount("/dev/ram", "/tmp", "ext2", 0, NULL))
  525.         fatal_error(1);
  526.  
  527.     printf("done\n");
  528.  
  529.     if (!nfsRoot) cdRoot = 1;
  530.     }
  531.  
  532.     /* Now we have some /tmp space set up, and /etc and /dev point to
  533.        it. We should be in pretty good shape. */
  534.  
  535.     /* Go into normal init mode - keep going, and then do a orderly shutdown
  536.        when:
  537.  
  538.     1) /bin/install exits
  539.     2) we receive a SIGHUP 
  540.     */
  541.  
  542.     printf("running install...\n");
  543.     if (!(installpid = fork())) {
  544.     /* child */
  545.     if (nfsRoot) {
  546.         symlink("/", "/tmp/rhimage");
  547.         symlink("/", "/tmp/image");
  548.         execl("/usr/bin/runinstall2", "/usr/bin/runinstall2", "--method",
  549.           "nfs", isRescue ? "--rescue" : NULL, NULL);
  550.     } else if (cdRoot) {
  551.         symlink("/", "/tmp/rhimage");
  552.         symlink("/", "/tmp/image");
  553.  
  554. #        if defined(__alpha__)
  555.         kernel = findKernel();
  556.  
  557.         if (kernel) 
  558.             execl("/usr/bin/runinstall2", "/usr/bin/runinstall2", 
  559.                 "--method", "cdrom", "--kernel", kernel, 
  560.                 isRescue ? "--rescue" : NULL, NULL);
  561.         else
  562.             execl("/usr/bin/runinstall2", "/usr/bin/runinstall2", 
  563.                 "--method", "cdrom", 
  564.                 isRescue ? "--rescue" : NULL, NULL);
  565. #        else
  566.         execl("/usr/bin/runinstall2", "/usr/bin/runinstall2", 
  567.                 "--method", "cdrom", 
  568.                   isRescue ? "--rescue" : NULL, NULL);
  569. #        endif
  570.     } else {
  571.         execl("/bin/install", "/bin/install", 
  572.            isRescue ? "--rescue" : NULL, NULL);
  573.     }
  574.  
  575.     exit(0);
  576.     }
  577.  
  578.     while (!doShutdown) {
  579.     childpid = wait(&waitStatus);
  580.  
  581.     if (childpid == installpid) 
  582.         doShutdown = 1;
  583.     }
  584.  
  585.     if (!WIFEXITED(waitStatus)) {
  586.     printf("install exited abnormally ");
  587.     if (WIFSIGNALED(waitStatus)) {
  588.         printf("-- recieved signal %d", WTERMSIG(waitStatus));
  589.     }
  590.     printf("\n");
  591.     } else {
  592.     doReboot = 1;
  593.     }
  594.  
  595.     if (testing)
  596.         exit(0);
  597.  
  598.     sync(); sync();
  599.  
  600.     if (!testing) {
  601.     printf("sending termination signals..."); fflush(stdout);
  602.     kill(-1, SIGTERM);
  603.     sleep(2);
  604.     printf("done\n");
  605.  
  606.     printf("sending kill signals..."); fflush(stdout);
  607.     kill(-1, SIGKILL);
  608.     sleep(2);
  609.     printf("done\n");
  610.     }
  611.  
  612.     printf("unmounting filesystems...\n"); 
  613.     unmountFilesystems();
  614.  
  615.     if (doReboot) {
  616.     printf("rebooting system\n");
  617.     sleep(2);
  618.  
  619.     #ifdef __alpha__
  620.         reboot(RB_AUTOBOOT);
  621.     #else
  622.         reboot(0xfee1dead, 672274793, 0x1234567);
  623.     #endif
  624.     } else {
  625.     printf("you may safely reboot your system\n");
  626.     while (1);
  627.     }
  628. }
  629.